//给你一个下标从 0 开始、长度为 n 的整数数组 nums ，和两个整数 lower 和 upper ，返回 公平数对的数目 。 
//
// 如果 (i, j) 数对满足以下情况，则认为它是一个 公平数对 ： 
//
// 
// 0 <= i < j < n，且 
// lower <= nums[i] + nums[j] <= upper 
// 
//
// 
//
// 示例 1： 
//
// 
//输入：nums = [0,1,7,4,4,5], lower = 3, upper = 6
//输出：6
//解释：共计 6 个公平数对：(0,3)、(0,4)、(0,5)、(1,3)、(1,4) 和 (1,5) 。
// 
//
// 示例 2： 
//
// 
//输入：nums = [1,7,9,2,5], lower = 11, upper = 11
//输出：1
//解释：只有单个公平数对：(2,3) 。
// 
//
// 
//
// 提示： 
//
// 
// 1 <= nums.length <= 10⁵ 
// nums.length == n 
// -10⁹ <= nums[i] <= 10⁹ 
// -10⁹ <= lower <= upper <= 10⁹ 
// 
//
// Related Topics 数组 双指针 二分查找 排序 👍 109 👎 0

package leetcode.editor.cn;

import java.util.Arrays;

//java:统计公平数对的数目
public class Q2563CountTheNumberOfFairPairs {
    public static void main(String[] args){
        Solution solution = new Q2563CountTheNumberOfFairPairs().new Solution();
        solution.countFairPairs(new int[]{0,1,7,4,4,5}, 3, 6);
    }
    //leetcode submit region begin(Prohibit modification and deletion)
class Solution {
    public long countFairPairs(int[] nums, int lower, int upper) {
        Arrays.sort(nums);
        int n = nums.length, res = 0;
//        for (int i = 0; i < n; i++) {
//            for (int j = i + 1; j < n; j++) {
//                if (nums[i] + nums[j] <= upper && nums[i] + nums[j] >= lower) {
//                    res++;
//                }
//                if (nums[i] + nums[j] > upper) {
//                    break;
//                }
//            }
//        }
//        return res;

        Arrays.sort(nums);
        long ans = 0;
        for (int j = 0; j < nums.length; j++) {
            // 注意要在 [0, j-1] 中二分，因为题目要求两个下标 i < j
            int r = lowerBound(nums, j, upper - nums[j] + 1);
            int l = lowerBound(nums, j, lower - nums[j]);
            ans += r - l;
        }
        return ans;
    }

        // 原理请看 https://www.bilibili.com/video/BV1AP41137w7/
        private int lowerBound(int[] nums, int right, int target) {
            int left = -1;
            while (left + 1 < right) {
                int mid = (left + right) >>> 1;
                if (nums[mid] >= target) {
                    right = mid;
                } else {
                    left = mid;
                }
            }
            return right;
        }


    }

//leetcode submit region end(Prohibit modification and deletion)

}